#!/usr/bin/php
<?php

// {{{ class dnsAP

/**
 * dnspod API 1.5所有接口的封装
 *
 * @author mahuzi QQ:738148
 */
class dnsAP
{
    // {{{ members

    /**
     * dnspod 用户帐号名
     *
     * @var string
     */
    private $user = '';

    /**
     * dnspod 用户帐号密码
     *
     * @var string
     */
    private $pass = '';
    
    /**
     * api交互数据格式 还可以是xml
     *
     * @var string
     */
    private $data_type = 'json';
    
    /**
     * dnspod api 主机url
     *
     * @var string
     */
    private $base_url = 'http://www.dnspod.com';
    
    /**
     * 本应用名称
     *
     * @var string
     */
    public $app_name = 'DnsAP(Dnspod Api for PHP)';
    
    /**
     * 本应用版本
     *
     * @var string
     */
    public $version = '0.1 QQ:738148';
    
    /**
     * 调式模式，http通讯协议的调试，api会抛异常
     *
     * @var boolean
     */
    public $debug = false;

    // }}} members end
    // {{{ functions 

    // {{{ function __construct()

    /**
     * 构造函数
     *
     * @param string $u dnspod用户账户
     * @param string $p dnspod账户密码
     *
     * @return void
     */
    public function __construct($u, $p) 
    {
        if (!function_exists('curl_init')) {
            throw new exception("php need curl module support!", 0);
        }
        
        if (!function_exists('json_decode')) {
            throw new exception("php need json function support!", 0);
        }

        $this->set_login_info($u, $p);
    }
    
    // }}}
    // {{{ function set_login_info()

    /**
     * 设置用户账户信息
     *
     * @param string $u dnspod用户账户
     * @param string $p dnspod账户密码
     *
     * @return void
     */
    public function set_login_info($u, $p)
    {
        $this->user = $u;
        $this->pass = $p;
    }

    // }}}
    // {{{ function get_base_params()

    /**
     * 获取post提交给api的默认参数
     *
     * @param void
     *
     * @return array
     */
    private function get_base_params()
    {
        return array(
                'login_email' => $this->user,
                'login_password' => $this->pass,
                'format' => $this->data_type,
                );
    }

    // }}}
    // {{{ function post()

    /**
     * API通讯接口
     *
     * @param string $method 跟api类型 例如 Domain.List
     * @param array $data 除上述基本参数外的额外参数
     *
     * @return string
     */
    private function post($method, $data)
    {
        $url = $this->base_url . '/API/' . $method;
        $data = array_merge($this->get_base_params(), $data);
        $_data = array();
        foreach ($data as $k => $v) {
           $_data[] = $k . '=' . rawurlencode($v);
        }

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, intval($this->debug));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_VERBOSE, intval($this->debug));
        curl_setopt($ch, CURLOPT_USERAGENT, $this->app_name . '/' . $this->version);
        curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $_data));

        $info = curl_exec($ch);

        $errno = curl_errno($ch);
        if (0 !== $errno) {
            $error = curl_error($ch);
            throw new exception($error, $errno);
        }

        curl_close($ch);
        if ($this->data_type === 'json') {
            $info = json_decode($info);
        } else {
            //to do list
            //这里解析XML格式
        }

        if (!is_array($info) && !is_object($info)) {
            throw new exception('parse data fail!', 10001);
        }
        return $info;
    }

    // }}}
    // {{{ function get_version()

    /**
     * 获取API版本信息
     *
     * @param void
     *
     * @return string
     */
    public function get_version()
    {
        $info = $this->post('Info.Version', array()); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        if ($info->status->code === -1) {
            throw new exception('error username or password', 10002);
        }

        return $info->status->message;
    }

    // }}}
    // {{{ function get_domain_list()
    
    /**
     * 获取域名列表
     *
     * @param string $grade  用户分类，共分为Free，Express，Extra，Ultra四类
     *
     * @return array
     */
    public function get_domain_list($grade = 'Free')
    {
        $info = $this->post('Domain.List', array('grade' => $grade)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return $info->domains->domain;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('empty domain list', 10005);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }

    }

    // }}}
    // {{{ function get_record_list()
    
    /**
     * 获取记录列表
     * 
     * @param int $domain_id
     *
     * @return array
     */
    public function get_record_list($domain_id)
    {
        $info = $this->post('Record.List', array('domain_id' => $domain_id)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return $info->records->record;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            case 7:
                throw new exception('empty record', 10008);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function create_record()
    
    /**
     * 创建新记录
     * 
     * @param int $domain_id      域名ID
     * @param string $sub_domain  子域名 例如 www
     * @param string $record_type {'A','CNAME','MX','URL','NS','TXT','AAAA'} 
     * @param string $value       记录值, 如 IP:200.200.200.200, CNAME: cname.dnspod.com., MX: mail.dnspod.com.
     * @param string $record_line {'default', 'tel', 'cnc', 'edu', 'cmc', 'foreign'} - 记录线路依次为：默认、电信、网通、教育网、移动、国外
     * @param int $mx             {1-20} - MX优先级, 当记录类型是 MX 时有效，范围1-20
     * @param int $ttl            {1-604800} - TTL，范围1-604800
     *
     * @return object {id:xxx, name:'xxxx'}
     */
    public function create_record($domain_id, $sub_domain='', $record_type, $value, $record_line='default', $ttl=600, $mx=10)
    {
        $sub_domain = strtolower($sub_domain);

        $allow_record_type = array('A'=>true, 'CNAME'=>true, 'MX'=>true, 'URL'=>true, 'NS'=>true, 'TXT'=>true, 'AAAA'=>true);
        $record_type = strtoupper($record_type);
        if (!isset($allow_record_type[$record_type]) || !$allow_record_type[$record_type]) {
            throw new exception('record type error', 10009);
        }

        $allow_record_line = array('default'=>true, 'tel'=>true, 'cnc'=>true, 'edu'=>true, 'cmc'=>true, 'foreign'=>true);
        if (!isset($allow_record_line[$record_line]) || !$allow_record_line[$record_line]) {
            throw new exception('record line error', 10010);
        }

        if ($ttl < 1 || $ttl > 604800) {
            throw new exception('record ttl error', 10011);
        }

        if ($record_type === 'MX' && ($mx <1 || $mx > 20)) {
            throw new exception('record mx error', 10012);
        }

        $info = $this->post('Record.Create', array('domain_id' => $domain_id, 'sub_domain' => $sub_domain,
                        'record_type' => $record_type, 'value' => $value, 'record_line' => $record_line,
                        'ttl' => $ttl, 'mx' => $mx,
                    )); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return $info->record;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            case 7:
                throw new exception('param error', 10014);
                break;
            case 8:
                throw new exception('domain record error', 10015);
                break;
            case 9:
                throw new exception('record value error', 10016);
                break;
            case 10:
                throw new exception('can not set NS type for "@" record', 10017);
                break;
            case 11:
                throw new exception('TTL need more than 1', 10018);
                break;
            case 12:
                throw new exception('MX need more than 1', 10019);
                break;
            case 13:
                throw new exception('duplicate record, or conflict with CNAME record', 10020);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function modify_record()
    
    /**
     * 更新记录
     * 
     * @param int $domain_id      域名ID
     * @param int $record_id      记录ID
     * @param string $sub_domain  子域名 例如 www
     * @param string $record_type {'A','CNAME','MX','URL','NS','TXT','AAAA'} 
     * @param string $value       记录值, 如 IP:200.200.200.200, CNAME: cname.dnspod.com., MX: mail.dnspod.com.
     * @param string $record_line {'default', 'tel', 'cnc', 'edu', 'cmc', 'foreign'} - 记录线路依次为：默认、电信、网通、教育网、移动、国外
     * @param int $mx             {1-20} - MX优先级, 当记录类型是 MX 时有效，范围1-20
     * @param int $ttl            {1-604800} - TTL，范围1-604800
     *
     * @return object {id:xxx, name:'xxxx'}
     */
    public function modify_record($domain_id, $record_id, $sub_domain='', $record_type, $value, $record_line='default', $ttl=600, $mx=10)
    {
        $sub_domain = strtolower($sub_domain);

        $allow_record_type = array('A'=>true, 'CNAME'=>true, 'MX'=>true, 'URL'=>true, 'NS'=>true, 'TXT'=>true, 'AAAA'=>true);
        $record_type = strtoupper($record_type);
        if (!isset($allow_record_type[$record_type]) || !$allow_record_type[$record_type]) {
            throw new exception('record type error', 10009);
        }

        $allow_record_line = array('default'=>true, 'tel'=>true, 'cnc'=>true, 'edu'=>true, 'cmc'=>true, 'foreign'=>true);
        if (!isset($allow_record_line[$record_line]) || !$allow_record_line[$record_line]) {
            throw new exception('record line error', 10010);
        }

        if ($ttl < 1 || $ttl > 604800) {
            throw new exception('record ttl error', 10011);
        }

        if ($record_type === 'MX' && ($mx <1 || $mx > 20)) {
            throw new exception('record mx error', 10012);
        }

        $info = $this->post('Record.Modify', array('domain_id' => $domain_id, 'sub_domain' => $sub_domain,
                        'record_type' => $record_type, 'value' => $value, 'record_line' => $record_line,
                        'ttl' => $ttl, 'mx' => $mx, 'record_id' => $record_id,
                    )); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return $info->record;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            case 7:
                throw new exception('param error', 10014);
                break;
            case 8:
                throw new exception('domain record error', 10015);
                break;
            case 9:
                throw new exception('record value error', 10016);
                break;
            case 10:
                throw new exception('can not set NS type for "@" record', 10017);
                break;
            case 11:
                throw new exception('TTL need more than 1', 10018);
                break;
            case 12:
                throw new exception('MX need more than 1', 10019);
                break;
            case 13:
                throw new exception('duplicate record, or conflict with CNAME record', 10020);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function remove_record()
    
    /**
     * 删除记录
     * 
     * @param int $domain_id      域名ID
     * @param int $record_id      记录ID
     *
     * @return boolean
     */
    public function remove_record($domain_id, $record_id)
    {

        $info = $this->post('Record.Remove', array('domain_id' => $domain_id, 'record_id' => $record_id)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return true;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            case 7:
                throw new exception('record not exist', 10021);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function set_record_status()
    
    /**
     * 设置记录状态
     * 
     * @param int $domain_id      域名ID
     * @param int $record_id      记录ID
     * @param boolean $stauts     记录状态 true enable | false disable
     *
     * @return boolean
     */
    public function set_record_status($domain_id, $record_id, $status)
    {
        $status = $status ? 'enable' : 'disable';

        $info = $this->post('Record.Status', array('domain_id' => $domain_id, 'record_id' => $record_id, 'status' => $status)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return true;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            case 7:
                throw new exception('record not exist', 10021);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function create_domain()
    
    /**
     * 创建新域名
     * 
     * @param string $domain  没有 WWW, 如 dnspod.com
     *
     * @return object {id:000, punycode:'xxx'}
     */
    public function create_domain($domain)
    {
        $domain = strtolower($domain);


        $info = $this->post('Domain.Create', array('domain' => $domain)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return $info->domain;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain error', 10022);
                break;
            case 5:
                throw new exception('domain exist', 10023);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function remove_domain()
    
    /**
     * 删除域名
     * 
     * @param int $domain_id
     *
     * @return boolean
     */
    public function remove_domain($domain_id)
    {
        $info = $this->post('Domain.Remove', array('domain_id' => $domain_id)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return true;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function set_domain_status()
    
    /**
     * 设置域名状态
     * 
     * @param int $domain_id  域名ID
     * @param boolean $status 域名状态 true enable | false disable
     *
     * @return boolean
     */
    public function set_domain_status($domain_id, $status)
    {
        $status = $status ? 'enable' : 'disable';
        $info = $this->post('Domain.Status', array('domain_id' => $domain_id, 'status' => $status)); 
        if (empty($info->status) || empty($info->status->code)) {
            throw new exception('parse data fail!', 10001);
        }

        switch ($info->status->code) {
            case -1:
                throw new exception('error username or password', 10002);
                break;
            case 1:
                return true;
            case 2:
                throw new exception('http method only access post', 10003);
                break;
            case 4:
                throw new exception('domain id error', 10006);
                break;
            case 5:
                throw new exception('domain not exist', 10007);
                break;
            case 6:
                throw new exception('not domain onwer', 10013);
                break;
            default:
                throw new exception('unknown error', 10004);
                break;
        }
    }

    // }}}
    // {{{ function detect_wan_ip()

    /**
     * 探测公网IP
     *
     * @param void
     *
     * @return string
     */
    private function detect_wan_ip()
    {
        $url = 'http://www.ip138.com/ip2city.asp';
        
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        $info = curl_exec($ch);

        $errno = curl_errno($ch);
        if (0 !== $errno) {
            $error = curl_error($ch);
            throw new exception($error, $errno);
        }

        curl_close($ch);

        if (preg_match('/\[(.+)\]/i', $info, $m)) {
             return $m[1];
        } else {
            return '';
        }
    }

    // }}}
    // {{{ function ddns_run()
    
    /**
     * 动态域名解析
     *
     * @param array $domains        需要动态解析的域名 支持多个域名多个记录解析 array('mahuzi.cn' => array('www', 'bbs'), ..., )
     * @param string $ip            要解析的目的IP地址
     * @param string $grade         用户类型
     * @param boolean $auto_active  是否自动设置状态为enable
     *
     * @return mix
     */
    public function ddns_run(array $domains, $ip='', $grade = 'Free', $auto_active = false)
    {
        if (empty($ip)) {
            $ip = $this->detect_wan_ip();
        }
        
        if (empty($ip)) {
            throw new exception("empty ip", 10024);
        }

        if (empty($domains)) {
            return true;
        }

        try {
            $domain_list = $this->get_domain_list($grade);
        } catch (exception $e) {
            $code = $e->getCode();
            if ($code != 10005) {
                throw $e;
            }

            $domain_list = array();
        }

        foreach ($domain_list as $k => $v) {
            if (isset($domains[$v->name])) {
                $domains[$v->name] = array('id' => $v->id, 'sub' => $domains[$v->name]);
                if (!$v->status && $auto_active) {
                    try {
                        $this->set_domain_status($v->id, true);
                    } catch (exception $e) {
                        continue;
                    }
                }
            }
        }

        $fail = array();

        foreach ($domains as $k => $v) {
            if (!isset($v['id'])) {
                //域名不存在，添加域名
                try {
                    $res = $this->create_domain($k);
                    $this_domain_id = $res->id;
                    $sub_domains = $v;
                } catch (exception $e) {
                    $fail[$k] = $v;
                    continue;
                }
            } else {
                $this_domain_id = $v['id'];
                $sub_domains = $v['sub'];
            }

            try {
                $records = $this->get_record_list($this_domain_id);
            } catch (exception $e) {
                if (10008 != $e->getCode()) {
                    $fail[$k] = $sub_domains;
                    continue;
                }

                $records = array();
            }

            $sub_domains = array_combine($sub_domains, $sub_domains);
            $_records = array();
            foreach ($records as $this_record) {
                if (isset($sub_domains[$this_record->name])) {
                    $_records[$this_record->id] = array('line' => $this_record->line, 'name' => $this_record->name); 
                    $sub_domains[$this_record->name] = false;
                    if (!$this_record->enabled && $auto_active) {
                        try {
                            $this->set_record_status($this_domain_id, $v->id, true);
                        } catch (exception $e) {
                            continue;
                        }
                    
                    }
                } 
            }

            //_records 
            foreach ($_records as $this_record_id => $rec) {
                try {
                    $this->modify_record($this_domain_id, $this_record_id, $rec['name'], 'A', $ip, $rec['line'], 600);
                } catch (exception $e) {
                    if (!isset($fail[$k])) {
                        $fail[$k] = array();
                    }

                    $fail[$k][] = $rec['name'];
                }
            }

            foreach ($sub_domains as  $this_sub_domain) {
                if (false === $this_sub_domain) {
                    continue;
                }
                try {
                    $this->create_record($this_domain_id, $this_sub_domain, 'A', $ip, 'default', 600);
                } catch (exception $e) {
                    if (!isset($fail[$k])) {
                        $fail[$k] = array();
                    }

                    $fail[$k][] = $this_sub_domain;
                }
            }
        } 

        if (empty($fail)) {
            return true;
        }

        return $fail;
    }

    // }}}

    // }}} functions end

}

// }}} class dnsAP end

// {{{ functino param()

/**
 * 命令行参数解析函数 由参数名获取参数值 参数名以"-"开头
 *
 * @param string $paramname 参数名 (以"-"开头,传参数省略"-")
 *
 * @return string 参数存在 string | 不存在 null 
 */
function param($paramname) {
    global $argv;

    $i = array_search('-' . $paramname, $argv);

    if ($i < 1) {//没有该参数
        return null;
    }

    $i++;

    if (!isset($argv[$i]) || '-' === substr($argv[$i], 0, 1)) {//没有值
        return '';
    }

    return $argv[$i];
}

// }}}

$user = param('user') ? param('user') : param('u');
$pass = param('pass') ? param('pass') : param('p');
$domain = param('domain');
$ip = param('ip');
$daemon = param('d') !== null ? param('d') : param('D');
$role = param('role') ? param('role') : param('r');
$help = param('help') === null ? param('help') : param('h');
$log = param('log') ? param('log') : param('l');

$helpinfo = <<<INFO
DnsAP(Dnspod Api for PHP) v0.1 QQ738148
Usage: ddns.php [options] 
Required parameters:
    -u, -user: dnspod username 
    -p, -pass: dnspod password
    -domain: domains struct information
        format: "topdomain1.com:subdomain1,subdomain2,...;topdomain2.com:dubdomain1,subdoman2,...;...;..."
        root record use '@'
        pan-record use '*'

Optional parameters:
    -ip: if set, this ip will be resolved and ignore dynamic ip. default use dynamic ip
    -d,-D:run application as a daemon,and update record every 600 seconds
    -r,-role:user type,default Free,you can use  Free，Express，Extra or Ultra
    -h,-help: show help information
    -l,-log: ouput log file path

INFO;

if (!$user || !$pass || !$domain || null !== $help) {
    echo $helpinfo;
    exit;
}

$_domain = array();
$tmp_domain = explode(';', $domain);
foreach ($tmp_domain as $v) {
    if (trim($v) === '') {
        continue;
    } 

    $domain_info = explode(':', $v);
    if (count($domain_info) !== 2) {
        continue;
    }

    $this_domain = $domain_info[0];
    $this_sub_domain = explode(',', $domain_info[1]);
    $_domain[$this_domain] = array();
    foreach ($this_sub_domain as $tmp) {
        if (trim($tmp) === '') {
            continue;
        }
        $_domain[$this_domain][] = $tmp;
    }

    if (empty($_domain[$this_domain])) {
        unset($_domain[$this_domain]);
    }
}

$app = new dnsAP($user, $pass);

function format_fail_domain($fail) {
    if (!is_array($fail)) {
        return '' ;
    }
    $error = array();
    foreach ($fail as $k => $v) {
        $error[] = $k . ':' . implode(',', $v);
    }

    return implode(';', $error);
}

if (null !== $daemon) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        exit("could not fork\n");
    } else if ($pid) {
        echo "ddns runing($pid), you can use kill $pid to termination of ddns\n";
        //父进程退出
        exit();
    } else {
        if (!$log) {
            $log = './ddns.log';
        }

        while(1) {
            try {
                $res = $app->ddns_run($_domain, $ip);
            } catch (exception $e) {
                $loginfo = $e->getMessage();     
                error_log(date('Y-m-d H:i:s', time()) . "\t" . $loginfo . "\n", 3, $log);
                exit;
            }

            if (true === $res) {
                $loginfo = "update records success";
            } else {
                $loginfo = "update records failure below:" . format_fail_domain($res);
            }
            
            error_log(date('Y-m-d H:i:s', time()) . "\t" . $loginfo . "\n", 3, $log);
            sleep(600);
        }
    }
} else {
    try {
        $res = $app->ddns_run($_domain, $ip);
    } catch (exception $e) {
        $loginfo = $e->getMessage();     
        echo $loginfo . "\n";
        exit;
    }
    if (true === $res) {
        echo "update record success\n";
    } else {
        echo "update records failure below:" . format_fail_domain($res) . "\n";
    }
}


